package com.android.UrbanRemix;

/**
 * AsyncTask runs in background and is an easy way to perform a background activity on Android.
 *  ImagePreviewManager shows progress dialog when image is downloading and address (through reverse geo-coding is fetched). 
 *  When image is retrieved it opens a Preview Dialog. 
 *  
 */

import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.location.Address;
import android.location.Geocoder;
import android.os.AsyncTask;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;

public class ImagePreviewManagerTask extends
		AsyncTask<PreviewTaskInputPayload, Void, ImagePayloadforAsyncTask> {

	private static final String TAG = "Image Preview Manager";

	// Progress dialog is shown first followed by Preview.
	ProgressDialog myPreviewProgressDialog;
	android.app.Dialog myPreviewDialog;
	ImageView markerImageView;
	Context mapContext;

	public ImagePreviewManagerTask(Context context) {
		this.mapContext = context;
	}

	@Override
	protected void onPreExecute() {

		myPreviewProgressDialog = ProgressDialog.show(mapContext,
				"Downloading Image", "Please wait...");

		myPreviewProgressDialog.setCancelable(true);

		// Cancel if download is taking too long. Go back to the map.
		myPreviewProgressDialog
				.setOnCancelListener(new DialogInterface.OnCancelListener() {

					public void onCancel(DialogInterface dialog) {
						Log.i("Async", "toDoInBackground Cancelled");

						// TODO At this point also recycle bitmap coz it
						// might've been downloaded, but .. how??? there's
						// no access to Bitmap from here.
						ImagePreviewManagerTask.this.cancel(true);
					}

				});

		// Call dismiss from onPostExecute() after image download completes
		myPreviewProgressDialog
				.setOnDismissListener(new DialogInterface.OnDismissListener() {

					public void onDismiss(DialogInterface dialog) {
						// Do nothing.
						Log.i("PreviewTask",
								"Dismissed coz image download successful");
						// PreviewTask.this.cancel(true);
					}
				});

	}

	@Override
	protected ImagePayloadforAsyncTask doInBackground(
			PreviewTaskInputPayload... params) {

		Log.i("PreviewTask: Image URL = ", params[0].getURL().toString());

		// Perform a reverse Geo-coding operation to get the address.
		String markerAddress = reverseGeocode(params[0].getLatitude(),
				params[0].getLongitude());

		/**
		 * Perform Image Download. Pack the Image and address string into
		 * ImagePayloadforAsyncTask.
		 */
		ImagePayloadforAsyncTask sendPayload = new ImagePayloadforAsyncTask(
				loadImageFromNetwork(params[0].getURL()), markerAddress);

		return sendPayload;

	}

	private String reverseGeocode(int latitude, int longitude) {
		Geocoder myGC = new Geocoder(mapContext);
		String line1 = null, line2 = null, line3 = null;

		try {
			List<Address> addresses = new ArrayList<Address>();
			addresses = myGC
					.getFromLocation(latitude / 1E6, longitude / 1E6, 1);

			line1 = addresses.get(0).getAddressLine(0);
			line2 = addresses.get(0).getAddressLine(1);
			line3 = addresses.get(0).getAddressLine(2);

			String output = new String();
			if (line1 != null)
				output = output.concat(line1);
			if (line2 != null)
				output = output.concat(" " + line2);
			if (line3 != null)
				output = output.concat(" " + line3);
			return output;

		} catch (IOException e) {
			Log.i(TAG, "Problem with address retrieval");
			return null;
		}

	}

	/**
	 * This method will query the remote image for dimensions and calculate the
	 * size of the image. If size > 0.5 MB, image is down-sampled and download
	 * operation is initiated. If for some reason image download still returns
	 * null (possibly because the server is not responding??), a default image
	 * (droidbot :) ) is downloaded.
	 * 
	 * @param imageURL
	 * @return Bitmap
	 */
	private Bitmap loadImageFromNetwork(URL imageURL) {
		try {

			int count = 0, maxTrials = 3; // No. of image download trials
			Bitmap bm = null;
			boolean isBmfull = false;

			while (!isBmfull && count < maxTrials) {
				URLConnection conn = imageURL.openConnection();
				conn.connect();
				BufferedInputStream bis = new BufferedInputStream(conn
						.getInputStream());

				// Get dimensions of image first.
				BitmapFactory.Options bfo = new BitmapFactory.Options();
				bfo.inJustDecodeBounds = true;
				bfo.inDither = false;
				bfo.inPreferredConfig = Bitmap.Config.RGB_565; // prob??

				// this line fills the bfo object.
				BitmapFactory.decodeStream(bis, null, bfo);

				Log.i("Image height", Integer.toString(bfo.outHeight));
				Log.i("Image width", Integer.toString(bfo.outWidth));

				// Downsample to keep image size in check.
				int maxFileSize = 324288; // in bytes. (~ 0.4 MB )
				int sampleSize = 1;
				long fileSize = 2 * (bfo.outWidth / sampleSize)
						* (bfo.outHeight / sampleSize);

				Log.i("Image size", Long.toString(fileSize));

				while (fileSize > maxFileSize) {
					sampleSize *= 2;
					fileSize = 2 * (bfo.outWidth / sampleSize)
							* (bfo.outHeight / sampleSize);

				}
				// Log.i("new Image size", Long.toString(fileSize));

				bis.close();

				/**
				 * new bfo parameters for actual image download is decoded using
				 * the calculated sample size
				 */
				bfo.inSampleSize = sampleSize;
				bfo.inJustDecodeBounds = false;
				bfo.inDither = false;

				// open a new URL connection
				URLConnection conn2 = imageURL.openConnection();
				conn2.connect();
				BufferedInputStream bis2 = new BufferedInputStream(conn2
						.getInputStream());

				bm = BitmapFactory.decodeStream(bis2, null, bfo);

				bis2.close();
				if (bm != null)
					isBmfull = true;

				count++;
			}

			if (isBmfull)
				return bm;
			else
				return loadDefaultUrbanRemixImage();

		} catch (IOException e) {

			Log.d("Image download", "I/O exception.");
			return loadDefaultUrbanRemixImage();

		}
	}

	/**
	 * Loads a default droid-bot image after trying to retrieve the original
	 * image from the server several times.
	 * 
	 * @return
	 */
	private Bitmap loadDefaultUrbanRemixImage() {

		URL defaultURL;
		try {
			defaultURL = new URL(
					"http://gadgetynews.com/wp-content/uploads/2009/04/android-300x300.jpg");

			URLConnection defaultConn = defaultURL.openConnection();
			defaultConn.connect();
			BufferedInputStream bis2 = new BufferedInputStream(defaultConn
					.getInputStream());

			return (BitmapFactory.decodeStream(bis2, null, null));
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		// TODO Instead of returning null, raise toast to say
		// "Cannot download Image. Try Again later."
		return null;
	}

	/**
	 * This method posts the PreviewDialog onto the UI after image download.
	 */

	protected void onPostExecute(ImagePayloadforAsyncTask payload) {
		myPreviewProgressDialog.dismiss();

		final Bitmap resultImage = payload.getPayloadImage();

		myPreviewDialog = new android.app.Dialog(mapContext);
		myPreviewDialog.setContentView(R.layout.image_preview_dialog);
		myPreviewDialog.setTitle("		Image Marker Preview");

		TextView addressview = (TextView) myPreviewDialog
				.findViewById(R.id.addresstext);
		if (payload.getAddress() != null)
			addressview.setText(payload.getAddress());
		else
			addressview.setText("No Address available");

		ImageView myPreviewImageView = (ImageView) myPreviewDialog
				.findViewById(R.id.itemimage);
		myPreviewImageView.setImageBitmap(resultImage);

		ImageButton close = (ImageButton) myPreviewDialog
				.findViewById(R.id.close);

		close.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {

				myPreviewDialog.dismiss();

			}
		});

		myPreviewDialog.show();

		myPreviewDialog
				.setOnCancelListener(new DialogInterface.OnCancelListener() {

					public void onCancel(DialogInterface dialog) {
						if (!resultImage.isRecycled()) {
							Log.i("Cancelled", "Bitmap recycling");
							resultImage.recycle();
						}

						if (ImagePreviewManagerTask.this.getStatus() == AsyncTask.Status.RUNNING)
							ImagePreviewManagerTask.this.cancel(true);
					}
				});

		myPreviewDialog
				.setOnDismissListener(new DialogInterface.OnDismissListener() {

					public void onDismiss(DialogInterface dialog) {

						/**
						 * If in case the preview dialog has opened without any
						 * image, then there is no image to recycle
						 */
						if (resultImage != null)
							if (!resultImage.isRecycled()) {
								Log.i("Dialog Dismissed", "Bitmap recycling");
								resultImage.recycle();
							}

						if (ImagePreviewManagerTask.this.getStatus() == AsyncTask.Status.RUNNING)
							ImagePreviewManagerTask.this.cancel(true);
					}
				});

	} // End of onPostExecute

}
